#include "sample_atmosphere.h"
#include "thread_pool.h"
constexpr double DEGREE = M_PI / 180.0;
#ifdef CUDA_ENABLE
const char* title = "atmosphere(GPU)";
#else
const char* title = "atmosphere(CPU)";
#endif
int main()
{
    FrameBuffer<color> frameBuffer{ 800,600 };
    auto d_target_image = (color*)d_malloc(frameBuffer.data_size());
    float theta = -90, altitude{ 1 };
    AtmosphereParamaters atmosParams{
        {0.f, PLANET_RADIUS, 0.f},
        { 0.f, float(cos(theta * DEGREE)), float(sin(theta * DEGREE)) } };

    bool need{ true };
    thread_pool threadPool(std::thread::hardware_concurrency());

    glShow(title, frameBuffer, GL_RGBA, [&threadPool, &theta, &altitude,&need, &atmosParams, &frameBuffer, d_target_image]()->long long
        {
            ImGui::Begin("Properties!");                          // Create a window called "Hello, world!" and append into it.
            need |= ImGui::SliderFloat("Degree", &theta, -100, 100);
            need |= ImGui::SliderFloat("Altitude", &altitude, 1, 100e3);
            ImGui::End();
            //theta += 2.5;
            //need = true;
            atmosParams.light_dir[1] = cos(theta * DEGREE), atmosParams.light_dir[2] = sin(theta * DEGREE);
            atmosParams.view_pos[1] = PLANET_RADIUS + altitude;
            if (!need)return 0;

            d_memcpy_to_symbol(atmosphere_paramaters, (const void*)&atmosParams, sizeof(AtmosphereParamaters));
            //uint32_t param_top{ 0 }, param_size{0};
            //d_memcpy(d_params, cam_pos, param_size + sizeof(cam_pos)); param_top += param_size;
            //d_memcpy(d_params + sizeof(cam_pos), light_dir, param_size = sizeof(light_dir)); param_top += param_size;
            
            synchronize();
            auto pre_time = std::chrono::high_resolution_clock::now();
#ifdef CUDA_ENABLE
            constexpr int threadPerBlock = 256;
            const auto allPixels = frameBuffer.width() * frameBuffer.height();
            const auto blockDim = dim3(32, threadPerBlock / 32);
            const auto blockCount = allPixels / threadPerBlock;
            const auto gridDim = dim3(32 , std::ceil(blockCount/32));
            atmosphere << <gridDim, blockDim >> > (d_target_image, frameBuffer.width(), frameBuffer.height());
#else
            //atmosphere(d_target_image, frameBuffer.width(), frameBuffer.height(), d_params, 395, 242, 0);
            std::vector<std::future<bool>> results;
            for (uint32_t y = 0; y < frameBuffer.height(); ++y)
            {
                results.push_back(std::move(threadPool.enqueue([&frameBuffer, d_target_image, y]()->bool {
                    for (uint32_t x = 0; x < frameBuffer.width(); ++x)
                        atmosphere(d_target_image, frameBuffer.width(), frameBuffer.height(),x, y, 0);
                    return true;
                    })));
            }
            for (auto& item : results)
                item.get();
#endif
            synchronize();
            auto duration = std::chrono::high_resolution_clock::now() - pre_time;

            d_memcpy(frameBuffer.data(), d_target_image, frameBuffer.data_size(), false);
            synchronize();
            frameBuffer.dirty = true;
            need = false;
            return duration.count();
        });

    d_free(d_target_image); 
    return 0;
}